package com.ypf.rpc.manager.server;

import com.ypf.rpc.annotation.RpcServer;
import com.ypf.rpc.annotation.RpcServerScan;
import com.ypf.rpc.factory.ServiceFactory;
import com.ypf.rpc.nettyHandler.HeartBeatServerHandler;
import com.ypf.rpc.nettyHandler.RpcRequestMessageHandler;
import com.ypf.rpc.procotol.MessageCodecSharable;
import com.ypf.rpc.procotol.ProcotolFrameDecoder;
import com.ypf.rpc.registery.ServerRegistry;
import com.ypf.rpc.registery.ServerRegistryImpl;
import com.ypf.rpc.utils.PackageScanUtils;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.timeout.IdleStateHandler;

import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * Rpc 服务端管理器
 */
public class RpcServiceManager {
    protected String host;
    protected int port;
    protected ServerRegistry serverRegistry;
    protected ServiceFactory serviceFactory;
    NioEventLoopGroup worker = new NioEventLoopGroup();
    NioEventLoopGroup boss = new NioEventLoopGroup();
    ServerBootstrap bootstrap = new ServerBootstrap();

    private List<Object> serverClasses;
    private List<String> serverNames;

    public RpcServiceManager(String host,int port){
        this.host = host;
        this.port = port;
        serviceFactory = new ServiceFactory();
        serverRegistry = new ServerRegistryImpl();
        autoRegistry();
    }

    /**
     * 自动扫描@RocServer注解 注册服务
     */
    public void autoRegistry(){
        String mainClassPath = PackageScanUtils.getStackTrace(); // 主类信息包名

        Class<?> mainClass;
        try {
            mainClass = Class.forName(mainClassPath);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            throw new RuntimeException("启动类未找到");
        }

        if (mainClass.isAnnotationPresent(RpcServer.class)){
            throw new RuntimeException("启动类缺少@RpcServer 注解");
        }

        // 看看 注解了RpcServerScan 的类是不是有值(目前没有赋值)
        String annotationValue = mainClass.getAnnotation(RpcServerScan.class).value();

        // 如果注解路径是空吗，则等于main父路径包下(上一级)
        if ("".equals(annotationValue)){
            annotationValue = mainClassPath.substring(0,mainClassPath.lastIndexOf(".")); // 截取掉main的名称
        }

        // 获取所有类的set集合
        Set<Class<?>> set = PackageScanUtils.getClasses(annotationValue);
        System.out.println("除主类所在的包，所有类数目为:"+set.size());


        serverClasses = new ArrayList();
        serverNames = new ArrayList<>();


        for (Class<?> c :set){
            // 只有@RpcServer注解才注册
            if (c.isAnnotationPresent(RpcServer.class)){
                String ServerNameValue = c.getAnnotation(RpcServer.class).name();
                Object object;

                try {
                    object = c.newInstance(); // 创建 c 的实例
                } catch (InstantiationException| IllegalAccessException e) {
                    e.printStackTrace();
                    System.err.println("创建对象" + c + "发生错误");
                    continue;
                }

                // 判断注解的值是否为空，为空使用类名
                if ("".equals(ServerNameValue)){
//                    addServer(object,c.getCanonicalName());    // 如:com.ypf.rpc.service.HelloServiceImpl
                    serverClasses.add(object);
                    serverNames.add(c.getCanonicalName());
                }else {
//                    addServer(object,ServerNameValue);
                    serverClasses.add(object);
                    serverNames.add(ServerNameValue);
                }
            }
        }

        for (int i = 0; i < serverClasses.size(); i++) {
            serviceFactory.addServiceProvider(serverClasses.get(i),serverNames.get(i));  // 将服务添加到工厂
        }

        // 单独开个线程执行
        ExecutorService executor = Executors.newSingleThreadExecutor();
        executor.submit(()->{
            serverRegistry.register(serverNames,new InetSocketAddress(host,port));
        });
    }

    /**
     * 添加对象到工厂和注册到注册中心
     * @param server
     * @param serverName
     * @param <T>
     */
    public <T> void addServer(T server,String serverName){  // server 是一个类对象 c.newInstance()
        serviceFactory.addServiceProvider(server,serverName);  // 将服务添加到工厂
//        serverRegistry.register(serverName,new InetSocketAddress(host,port));  // 注册到nacos中
    }

    /**
     * 开启服务
     */
    public void start(){
        // 日志
        LoggingHandler LOGGING = new LoggingHandler(LogLevel.DEBUG);

        // 自定义消息编解码器
        MessageCodecSharable MESSAGE_CODEC = new MessageCodecSharable();

        // PRC请求处理器
        RpcRequestMessageHandler RPC_HANDLER = new RpcRequestMessageHandler();

        // 心跳处理器
        HeartBeatServerHandler HEARTBEAT_SERVER = new HeartBeatServerHandler();

        try {
            bootstrap.group(boss,worker)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG,256)
//                    .option(ChannelOption.SO_KEEPALIVE,true)
//                    .option(ChannelOption.TCP_NODELAY,true)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            ChannelPipeline pipeline = socketChannel.pipeline();
                            pipeline.addLast(new IdleStateHandler(30,0,0, TimeUnit.SECONDS));
                            pipeline.addLast(new ProcotolFrameDecoder());  // 定长处理器
                            pipeline.addLast(MESSAGE_CODEC);
                            pipeline.addLast(LOGGING);
                            pipeline.addLast(HEARTBEAT_SERVER);
                            pipeline.addLast(RPC_HANDLER);
                        }
                    });
            // 绑定端口
            Channel channel = bootstrap.bind(port).sync().channel();
            channel.closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
            System.err.println("启动服务出错");
        }finally {
            worker.shutdownGracefully();
            boss.shutdownGracefully();
        }
    }


}
